using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using Amazon.ECS.Model;
using Castle.Core;
using RomanJendrusz.Amazon.ETL.Infrastructure.Bus;
using RomanJendrusz.Amazon.ETL.Infrastructure.Bus.RequestHandlers;
using RomanJendrusz.Amazon.ETL.Infrastructure.DataBase;
using RomanJendrusz.Amazon.ETL.Infrastructure.IoC;
using RomanJendrusz.Amazon.ETL.Infrastructure.IoC.Windsor;
using RomanJendrusz.Amazon.ETL.Infrastructure.Loging.Core;
using RomanJendrusz.Amazon.ETL.Messages;
using RomanJendrusz.Amazon.ETL.Messages.MessageMappers;
using RomanJendrusz.Amazon.ETL.Services;
using RomanJendrusz.Amazon.ETL.Tasks;
using Amazon.ECS;
using Amazon.ECS.Query;
using System.Collections;

namespace RomanJendrusz.Amazon.ETL
{
    public class AmazonETL
    {
        private static readonly object sync = new object();
        private static bool isInitialized;

        public static void Initialize()
        {
            if(isInitialized)
                return;
            lock (sync)
            {
                InitializeDependencies();
                isInitialized = true;
            }
        }

        private static void InitializeDependencies()
        {
            var windsorInitializer = new AppConfigWindsorInitializer();
            var resolver = new WindsorDependencyResolverAdapter(windsorInitializer);
            AddTasks(resolver);
            AddServices(resolver);
            AddRequestHandlers(resolver);
            AddMessageMappers(resolver);
            AddDataBaseConfiguration(resolver);
            AddAmazonQuery(resolver);
            var types = Assembly.GetExecutingAssembly().GetTypes()
                .Where(t => t.IsClass && t.IsAbstract == false && t.GetInterfaces().Length > 0);
            var assemblyTypes = types.Where(t => t.GetInterfaces().Where(i => i.Assembly == t.Assembly).Count() != 0);
            foreach (var type in assemblyTypes)
            {
                if (type == typeof(FileMappingSourceBuilder) || type == typeof(DataBaseConnectionFactory))
                {
                    continue;
                }
                if(type.GetInterfaces().Length > 1)
                {
                    resolver.AdoptedContainer.AddComponentWithLifestyle(
                       type.Name.ToLower(), type.GetInterfaces()[0], type, LifestyleType.Transient);
                }
                foreach (var service in type.GetInterfaces())
                {
                    var key = string.Format("{0}-{1}", type.Name.ToLower(), service.Name.ToLower());
                    resolver.AdoptedContainer.AddComponentWithLifestyle(key, service, type, LifestyleType.Transient);
                }
            }
            IoCGateway.Initialize(resolver);
        }

        private static void AddAmazonQuery(IDependencyResolver resolver)
        {
            resolver.AddComponent<AmazonECSFactory>(LifeStyle.Singletone);
        }

        private static void AddDataBaseConfiguration(WindsorDependencyResolverAdapter resolver)
        {
            var builder = new FileMappingSourceBuilder(ConfigurationManager.AppSettings["MappingFile"]);
            var connectionFactory = new DataBaseConnectionFactory(ConfigurationManager.ConnectionStrings["Amazon"]);
            resolver.AddInstance<IMappingSourceBuilder>(builder);
            resolver.AddInstance<IDataBaseConnectionFactory>(connectionFactory);
            resolver.AddComponent<DataBaseManager>(LifeStyle.Singletone);
        }

        private static void AddTasks(IDependencyResolver resolver)
        {
            resolver.AddComponent<BookTask>();
            resolver.AddComponent<SellerOfferTask>();
            resolver.AddComponent<CustomerReviewTask>();
        }

        private static void AddServices(IDependencyResolver resolver)
        {
            resolver.AddComponent<IBookService, BookService>();
        }

        private static void AddRequestHandlers(IDependencyResolver resolver)
        {
            resolver.AddComponent<ItemLookupRequestHandler>();
            resolver.AddComponent<SellerListingLookupRequestHandler>();
        }

        private static void AddMessageMappers(IDependencyResolver resolver)
        {
            resolver.AddComponent
                <MessageMapper<GetBookDetailsRequest, ItemLookupRequest, ItemLookupResponse>,
                    GetBookDetailsMessageMapper>();
            resolver.AddComponent<MessageMapper<GetSimiliarBooksRequest, ItemLookupRequest, ItemLookupResponse>,
                    GetSimiliarBooksMessageMapper>();
            resolver.AddComponent<MessageMapper<GetBookReviewsCountRequest, ItemLookupRequest, ItemLookupResponse>,
                    GetBookReviewsCountMapper>();
            resolver.AddComponent<MessageMapper<GetBookReviewsRequest, ItemLookupRequest, ItemLookupResponse>,
                    GetBookReviewsMapper>();
            resolver.AddComponent<MessageMapper<GetBookOffersRequest, ItemLookupRequest, ItemLookupResponse>,
                   GetBookOffersMapper>();
            resolver.AddComponent<MessageMapper<GetBookOffersCountRequest, ItemLookupRequest, ItemLookupResponse>,
                   GetBookOffersCountMapper>();
            resolver.AddComponent<MessageMapper<GetOfferDetailsRequest, SellerListingLookupRequest, SellerListingLookupResponse>,
                GetOfferDetailsMapper>();
            resolver.AddComponent<MessageMapper<GetBrowseNodesForProductRequest, ItemLookupRequest, ItemLookupResponse>,
                GetBrowseNodesForProductMapper>();
        }
    }
}